package com.pt25.gateway.dynamicroute;


import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery;
import com.alibaba.nacos.api.naming.listener.Event;
import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class EnhancedNacosServiceChangeListener {

    private final NacosDiscoveryProperties discoveryProperties;
    private final NacosServiceDiscovery serviceDiscovery;
    private final ApplicationEventPublisher eventPublisher;

    private final Set<String> subscribedServices = ConcurrentHashMap.newKeySet();
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
    private volatile boolean initialized = false;

    public EnhancedNacosServiceChangeListener(NacosDiscoveryProperties discoveryProperties,
                                              NacosServiceDiscovery serviceDiscovery,
                                              ApplicationEventPublisher eventPublisher) {
        this.discoveryProperties = discoveryProperties;
        this.serviceDiscovery = serviceDiscovery;
        this.eventPublisher = eventPublisher;
    }

    @PostConstruct
    public void init() {
        log.info("🚀 初始化Nacos服务动态发现监听器...");

        // 延迟启动，等待Gateway和Nacos连接就绪
        scheduler.schedule(this::initializeServiceDiscovery, 15, TimeUnit.SECONDS);

        // 定期检查服务变化
        scheduler.scheduleAtFixedRate(this::refreshAllServices, 30, 30, TimeUnit.SECONDS);
    }

    /**
     * 初始化服务发现
     */
    private void initializeServiceDiscovery() {
        try {
            if (!checkNacosConnection()) {
                log.warn("Nacos连接未就绪，10秒后重试...");
                scheduler.schedule(this::initializeServiceDiscovery, 10, TimeUnit.SECONDS);
                return;
            }

            // 订阅所有现有服务
            subscribeAllServices();

            // 标记初始化完成
            initialized = true;
            log.info("✅ Nacos服务动态发现监听器初始化完成");

        } catch (Exception e) {
            log.error("❌ Nacos服务发现初始化失败，10秒后重试", e);
            scheduler.schedule(this::initializeServiceDiscovery, 10, TimeUnit.SECONDS);
        }
    }

    /**
     * 检查Nacos连接状态
     */
    private boolean checkNacosConnection() {
        try {
            String serverStatus = discoveryProperties.namingServiceInstance().getServerStatus();
            log.info("Nacos服务器状态: {}", serverStatus);
            return "UP".equals(serverStatus);
        } catch (Exception e) {
            log.warn("Nacos连接检查失败: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 订阅所有现有服务
     */
    private void subscribeAllServices() {
        try {
            List<String> services = serviceDiscovery.getServices();
            log.info("📋 发现 {} 个已注册服务: {}", services.size(), services);

            if (services.isEmpty()) {
                log.info("当前没有注册的服务，等待服务注册...");
                return;
            }

            for (String service : services) {
                subscribeService(service);
            }

        } catch (Exception e) {
            log.error("获取服务列表失败", e);
        }
    }

    /**
     * 订阅单个服务变化
     */
    private void subscribeService(String serviceName) {
        if (subscribedServices.contains(serviceName)) {
            return;
        }

        try {
            // 获取当前服务实例
            List<ServiceInstance> instances = serviceDiscovery.getInstances(serviceName);
            log.info("🔍 服务 {} 当前有 {} 个实例", serviceName, instances.size());

            // 订阅服务变化
            discoveryProperties.namingServiceInstance().subscribe(serviceName, new EventListener() {
                @Override
                public void onEvent(Event event) {
                    if (event instanceof NamingEvent) {
                        handleServiceChange(serviceName, (NamingEvent) event);
                    }
                }
            });

            subscribedServices.add(serviceName);
            log.info("✅ 已订阅服务变化监听: {}", serviceName);

            // 立即触发一次路由刷新
            triggerRouteRefresh();

        } catch (Exception e) {
            log.error("订阅服务变化失败: {}", serviceName, e);
        }
    }

    /**
     * 处理服务变化事件
     */
    private void handleServiceChange(String serviceName, NamingEvent event) {
        log.info("🔄 服务实例变化 - 服务: {}, 实例数: {}",
                serviceName, event.getInstances().size());

        // 打印实例详情
        event.getInstances().forEach(instance ->
                log.debug("实例详情: {}:{} (健康: {}, 权重: {})",
                        instance.getIp(), instance.getPort(),
                        instance.isHealthy(), instance.getWeight())
        );

        // 触发路由刷新
        triggerRouteRefresh();
    }

    /**
     * 触发路由刷新
     */
    private void triggerRouteRefresh() {
        try {
            log.info("🔄 触发网关路由刷新...");
            eventPublisher.publishEvent(new RefreshRoutesEvent(this));

            // 记录刷新时间
            log.info("✅ 网关路由刷新事件已发布 - 时间: {}",
                    java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ISO_LOCAL_TIME));

        } catch (Exception e) {
            log.error("触发路由刷新失败", e);
        }
    }

    /**
     * 定期刷新所有服务订阅
     */
    private void refreshAllServices() {
        if (!initialized) {
            return;
        }

        try {
            List<String> currentServices = serviceDiscovery.getServices();
            log.debug("定期服务检查，当前共有 {} 个服务", currentServices.size());

            // 订阅新服务
            for (String service : currentServices) {
                if (!subscribedServices.contains(service)) {
                    log.info("🎯 发现新服务: {}", service);
                    subscribeService(service);
                }
            }

            // 清理已不存在的服务订阅
            subscribedServices.removeIf(service -> !currentServices.contains(service));

        } catch (Exception e) {
            log.error("刷新服务订阅失败", e);
        }
    }

    /**
     * 监听Spring事件，确保在合适时机重新初始化
     */
    @org.springframework.context.event.EventListener
    public void handleContextRefreshedEvent(org.springframework.context.event.ContextRefreshedEvent event) {
        log.info("🔄 Spring上下文刷新，重新初始化服务发现...");
        if (!initialized) {
            scheduler.schedule(this::initializeServiceDiscovery, 5, TimeUnit.SECONDS);
        }
    }
}